#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <pthread.h>
#include <math.h>
#include "prefetch_lib.h"
#include <time.h>
#include <pthread.h>

#define N (32768/2)
#define NUMINTS  (N * N)
#define FILESIZE (NUMINTS * sizeof(int))
#define TOTALSIZE (4294967296/2)

int *mapa, *mapb;

int F() 
{    
    int i, j, k, s, m = 0, l;
    time_t t = time(0);
    
    for (i = 0; i < N; ++i) {
//        printf("[%lu] in i loop; i = %d\n", pthread_self(), i);
        for (j = 0; j < N; ++j) {
            if (j % 256 == 0) {
              time_t n = time(0);
              printf("[%lu] in j loop; j = %d done in %lu\n", pthread_self(), j, n - t);
              t = n;
            }
            s = 0;
            for (k = 0; k < N; ++k) {
//                s += mapa[i * N + k] * mapb[k * N + j];
                for (l = 0; l < 16; ++l) {
                s += sin(sin(sin(sin(cos(cos(cos(sin(mapa[i * N + k]) * sin(mapb[k * N + j]))))))));
                s += sin(sin(sin(sin(cos(cos(cos(mapa[i * N + k] * sin(mapb[k * N + j]))))))));
                s += sin(sin(sin(sin(cos(cos(cos(mapa[i * N + k] * mapb[k * N + j])))))));
                }
/*
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
                s += mapa[i * N + k] * mapb[k * N + j];
*/
            }
            m ^= s;
        }
    }

    
    return m;
}

int main(int argc, char *argv[])
{
    int f, fda, fdb;

    turn_logging(1);
    fetch_init();
    mapa = (int*)mmap(0, FILESIZE, PROT_READ, MAP_SHARED, fda = open64("a", O_RDONLY), 0);
    if (mapa == MAP_FAILED) {
      perror("mapa");
      exit(1);
    }
    mapb = (int*)mmap(0, FILESIZE, PROT_READ, MAP_SHARED, fdb = open64("b", O_RDONLY), 0);


    printf("a: %x-%x\n", (unsigned int)mapa >> 12, (unsigned int)(mapa + N * N) >> 12);
    printf("b: %x-%x\n", (unsigned int)mapb >> 12, (unsigned int)(mapb + N * N) >> 12);

    madvise(mapa, FILESIZE, MADV_RANDOM);
    madvise(mapb, FILESIZE, MADV_RANDOM);    

    f = F();

    munmap(mapa, FILESIZE);
    munmap(mapb, FILESIZE);

    close(fda);
    close(fdb);

    return f;
}
